#!/usr/bin/env python3
#
# Copyright (c) [2020] Huawei Technologies Co.,Ltd.All rights reserved.
#
# OpenArkCompiler is licensed under the Mulan PSL v1.
# You can use this software according to the terms and conditions of the Mulan PSL v1.
# You may obtain a copy of Mulan PSL v1 at:
#
#     http://license.coscl.org.cn/MulanPSL
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR
# FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v1 for more details.
#

"""
mpl-collect-macro-defs: Collect the object layout information from *.macros.def
and emit a C/C++ header file that contains the necessary definitions.
"""

import argparse
import os.path
import sys
import re

DEFAULT_OUTPUT_FILE = "unified.macros.def"
line_pat = re.compile(r"(\w+)\((.*)\)")

def log(*args, **kwargs):
    print(*args, file=sys.stderr, **kwargs)

parser = argparse.ArgumentParser(description='''
mpl-collect-macro-defs: Collect the object layout information from *.macros.def
and emit a C/C++ header file that contains the necessary definitions.
''')

parser.add_argument('files', metavar='FILE',
        type=str, nargs='+',
        help='File (xxxx.macros.def) to be concatenated.')
parser.add_argument('-o', '--output', metavar="OUTFILE",
        type=str, default=DEFAULT_OUTPUT_FILE,
        help='Write to OUTFILE.  Default: {}'.format(DEFAULT_OUTPUT_FILE))

args = parser.parse_args()

for filename in args.files:
    if not os.path.exists(filename):
        print("{}: File does not exist".format(filename))
        sys.exit(1)

lines = []

for filename in args.files:
    with open(filename, "r") as f:
        my_lines = f.read().splitlines()
        lines.extend(my_lines)

lines_set = set(lines)

file_template = """\
// This file is generated by mapleall/maplebe/collect/mpl-collect-groot-lists.
// Do not modify manually.
#ifndef __THE_UNIFIED_MACROS_DEF__
#define __THE_UNIFIED_MACROS_DEF__
{definitions}
#endif // __THE_UNIFIED_MACROS_DEF__
"""

class_template = """\
#define __MRT_instance_size__{classname} {instance_size}
extern void *MCC_GCTIB__{classname};
extern void (*__itab__{classname})();
extern void (*__vtab__{classname})();
extern void *__classinfo__{classname};
"""

field_template = """\
#define __MRT_field_offset__{classname}__{fieldname} {field_offset}
#define __MRT_field_size__{classname}__{fieldname} {field_size}
"""

log("Generating file...")

def render_class(content):
    classname, instance_size = content.split(",")
    classname = classname.strip()
    instance_size = instance_size.strip()
    return class_template.format(
            classname = classname,
            instance_size = instance_size,
            )

def render_class_field(content):
    classname, fieldname, field_offset, field_size = content.split(",")
    classname = classname.strip()
    fieldname = fieldname.strip()
    field_offset = field_offset.strip()
    field_size = field_size.strip()
    return field_template.format(
            classname = classname,
            fieldname = fieldname,
            field_offset = field_offset,
            field_size = field_size,
            )

def render_line(line):
    tag, content = line_pat.findall(line)[0]
    if tag == "__MRT_CLASS":
        return render_class(content)
    elif tag == "__MRT_CLASS_FIELD":
        return render_class_field(content)
    else:
        raise Exception("Unexpected tag: " + tag)

def render_file():
    results = []
    for line in lines_set:
        result = render_line(line)
        results.append(result)

    return file_template.format(definitions="".join(results))

file_rendered = render_file()

log("Writing to {} ...".format(args.output))

with open(args.output, "w") as f:
    f.write(file_rendered)

log("Done.")

#vim: tw=80 ts=4 sw=4 sts=4 et ai
